﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SolarWinds.Helpers;
using SolarWinds.Shapes;

namespace SolarWinds.Renderers
{
    class BoundingSphereRenderer : DrawableGameComponent
    {
        private const int SampleCount = 40;

        private VertexBuffer mVertexBuffer;
        private VertexDeclaration mVertexDeclaration;
        private BasicEffect mBasicEffect;

        public Color LineColor = Color.Yellow;

        public GameComponentCollection Components;

        public BoundingSphereRenderer(Game game) : base(game)
        {
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            GraphicsDevice device = Game.GraphicsDevice;

            device.Vertices[0].SetSource(mVertexBuffer, 0, VertexPositionColor.SizeInBytes);
            device.VertexDeclaration = mVertexDeclaration;

            DrawSpheres(Components);
        }

        private void DrawSpheres(GameComponentCollection componentCollection)
        {
            GraphicsDevice device = Game.GraphicsDevice;

            foreach (IGameComponent component in componentCollection)
            {
                var shape = component as Shape;
                if (shape != null)
                {
                    if (shape.BoundingSphereVisible)
                    {
                        // create world matrix
                        Matrix bsWorld = Matrix.CreateScale(shape.BoundingSphere.Radius) * shape.World;

                        // set effect parameters
                        mBasicEffect.World = bsWorld;
                        mBasicEffect.View = SolarWindsGame.Camera.View;
                        mBasicEffect.Projection = SolarWindsGame.Camera.Projection;
                        mBasicEffect.DiffuseColor = LineColor.ToVector3();
                        mBasicEffect.CommitChanges();

                        mBasicEffect.Begin();
                        foreach (EffectPass pass in mBasicEffect.CurrentTechnique.Passes)
                        {
                            pass.Begin();

                            device.DrawPrimitives(PrimitiveType.LineStrip, 0, SampleCount - 1);
                            device.DrawPrimitives(PrimitiveType.LineStrip, SampleCount, SampleCount - 1);
                            device.DrawPrimitives(PrimitiveType.LineStrip, SampleCount * 2, SampleCount - 1);

                            pass.End();
                        }
                        mBasicEffect.End();    
                    }
                }

                var drawableComponentManager = component as DrawableComponentManager;
                if (drawableComponentManager != null)
                {
                    DrawSpheres(drawableComponentManager.Components);
                }
            }
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            GraphicsDevice device = Game.GraphicsDevice;

            // basic effect
            mBasicEffect = new BasicEffect(device, null);

            // vertex buffer
            mVertexBuffer = new VertexBuffer(device, typeof(VertexPositionColor),
                                             3 * SampleCount, BufferUsage.WriteOnly);
            var data = new VertexPositionColor[3 * SampleCount];

            var sinSamples = new float[SampleCount];
            var cosSamples = new float[SampleCount];

            for (int i = 0; i < SampleCount; ++i)
            {
                sinSamples[i] = (float)Math.Sin(2 * Math.PI * i / (SampleCount - 1));
                cosSamples[i] = (float)Math.Cos(2 * Math.PI * i / (SampleCount - 1));
            }

            int vi = 0;

            // loop in xy plane
            for (int i = 0; i < SampleCount; ++i)
            {
                data[vi].Position = new Vector3(cosSamples[i], sinSamples[i], 0.0f);
                data[vi].Color = Color.Yellow;
                ++vi;
            }

            // loop in xz plane
            for (int i = 0; i < SampleCount; ++i)
            {
                data[vi].Position = new Vector3(cosSamples[i], 0.0f, sinSamples[i]);
                data[vi].Color = Color.Yellow;
                ++vi;
            }

            // loop in yz plane
            for (int i = 0; i < SampleCount; ++i)
            {
                data[vi].Position = new Vector3(0.0f, cosSamples[i], sinSamples[i]);
                data[vi].Color = Color.Yellow;
                ++vi;
            }

            mVertexBuffer.SetData(data);

            // vertex declaration
            mVertexDeclaration = new VertexDeclaration(device, VertexPositionColor.VertexElements);
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();

            if (mVertexBuffer != null)
            {
                mVertexBuffer.Dispose();
                mVertexBuffer = null;
            }

            if (mVertexDeclaration != null)
            {
                mVertexDeclaration.Dispose();
                mVertexDeclaration = null;
            }

            if (mBasicEffect != null)
            {
                mBasicEffect.Dispose();
                mBasicEffect = null;
            }
        }
    }
}
